package jp.sourceforge.akjrcp.flvtools.explorer;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import jp.sourceforge.akjrcp.akj_betas.Akj_betasPlugin;
import jp.sourceforge.akjrcp.commons.util.FileNameUtils;
import jp.sourceforge.akjrcp.dropsomething.PSPConvertTabBuilder;
import jp.sourceforge.akjrcp.ffmpeg.FFMpegCommandUtil;
import jp.sourceforge.akjrcp.ffmpeg.FFMpegFLVParser;
import jp.sourceforge.akjrcp.ffmpeg.FFMpegInput;
import jp.sourceforge.akjrcp.ffmpeg.FFMpegOptions;
import jp.sourceforge.akjrcp.ffmpeg.FFMpegPreference;
import jp.sourceforge.akjrcp.ffmpeg.FFMpegUI;
import jp.sourceforge.akjrcp.ffmpeg.FFMpegUtils;
import jp.sourceforge.akjrcp.ffmpeg.FLVInfomation;
import jp.sourceforge.akjrcp.ffmpeg.SimpleCommandExecuter;
import jp.sourceforge.akjrcp.flvtools.basic.AVISettingPage;
import jp.sourceforge.akjrcp.flvtools.basic.MPEGSettingPage;
import jp.sourceforge.akjrcp.flvtools.basic.ShareSettingPage;
import jp.sourceforge.akjrcp.flvtools.basic.WMVSettingPage;
import jp.sourceforge.akjrcp.psp.OldPSPSettingPage;
import jp.sourceforge.akjrcp.psp.PSPFFMpegPreference;
import jp.sourceforge.akjrcp.psp.PSPMovieSetting;
import jp.sourceforge.akjrcp.psp.PSPMovieSettingTableViewer;
import jp.sourceforge.akjrcp.util.ProcessMonitor;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.ui.PlatformUI;

public class FFMpegExplorerExecuter extends Thread{
	public static Log log = LogFactory.getLog(FFMpegExplorerExecuter.class);
	private String extension;
	private File[] convertingFile;
	//IProgressMonitor convertMonitor;
	


	
	private File exportBaseDir;
	private ExplorerView ffmpegExecutable;
	public FFMpegExplorerExecuter(ExplorerView ffmpegExecutable){
		this.ffmpegExecutable=ffmpegExecutable;

	}
	
	private boolean converting=true;
	private Process currentProcess;
	
	public void cancel(){
		if(currentProcess!=null){
		currentProcess.destroy();
		}
		converting=false;
	}
	public void debugArray(String[] array){
		String v="";
		for (int i = 0; i < array.length; i++) {
			v+="\""+array[i]+"\""+" ";
		}
		Akj_betasPlugin.getDefault().getProcessPrinter().printOutput(v+"\n");
	}
	
	public static boolean isImageExport(String extension){
		return extension.equals("png") || extension.equals("jpg") || extension.equals("gif");
	}
	
	public void startExecute(){
		ffmpegExecutable.startExecute(convertingFile);
		//ffmpegExecutable.
		this.start();
	}
	
	/*
	 * support only mpg
	 */
	public static boolean canPureFFMpeg(String extension){
		IPreferenceStore store=Akj_betasPlugin.getDefault().getPreferenceStore();
		boolean ret=false;
		
		if(isImageExport(extension)){
			return true;
		}else if(extension.equals("wav")){
			return true;
		}
		else if(extension.equals("avi")){
			boolean canvideo=false;
			String avicodec=store.getString(AVISettingPage.AVI_VIDEO_CODEC);
			String canvideos[]={FFMpegOptions.CODEC_COPY,FFMpegOptions.CODEC_VIDEO_HUFFYUV,FFMpegOptions.CODEC_VIDEO_MJPEG,FFMpegOptions.CODEC_VIDEO_MSMPEG4V1,FFMpegOptions.CODEC_VIDEO_MSMPEG4V2};
			for (int i = 0; i < canvideos.length; i++) {
				if(canvideos[i].equals(avicodec)){
					canvideo=true;
					break;
				}
			}
			if(canvideo){
				String audiocodec=store.getString(AVISettingPage.AVI_AUDIO_CODEC);
				String canaudios[]={FFMpegOptions.NONE,FFMpegOptions.CODEC_COPY,FFMpegOptions.CODEC_AUDIO_WAV,FFMpegOptions.CODEC_AUDIO_WMA1,FFMpegOptions.CODEC_AUDIO_WMA2};
				for (int i = 0; i < canaudios.length; i++) {
					if(canaudios[i].equals(audiocodec)){
						return true;
					}
				}
			}
			
		}else if(extension.equals("wmv")){
			String audiocodec=store.getString(WMVSettingPage.WMV_AUDIO_CODEC);
			String canaudios[]={FFMpegOptions.CODEC_COPY,FFMpegOptions.CODEC_AUDIO_WAV,FFMpegOptions.CODEC_AUDIO_WMA1,FFMpegOptions.CODEC_AUDIO_WMA2};
			for (int i = 0; i < canaudios.length; i++) {
				if(canaudios[i].equals(audiocodec)){
					return true;
				}
			}
			
		}else if(extension.equals("mpg")){
			String audiocodec=store.getString(MPEGSettingPage.MPEG_AUDIO_CODEC);
			String canaudios[]={FFMpegOptions.CODEC_AUDIO_MP2};
			for (int i = 0; i < canaudios.length; i++) {
				if(canaudios[i].equals(audiocodec)){
					return true;
				}
			}
		}
		
		return ret;
	}
	
	
	public void run(){
		File tmpAudio=null;
		File tmpVideo=null;
		
		IPreferenceStore store=Akj_betasPlugin.getDefault().getPreferenceStore();
		String ffmpegPath;
		if(canPureFFMpeg(extension)){
		log.info("can pure ffmpeg.exe");
		ffmpegPath=FFMpegUI.getFFmpegOrPureFFMpeg();	
		}else{
		ffmpegPath=FFMpegUI.getFFmpeg();
		}
		log.info(ffmpegPath);
		if(ffmpegPath==null){
			cancel();
			return;
		}
		
		boolean fileDeleted=false;//for delete convert flv.
		int generation=FFMpegUtils.getFFMpegGeneration(ffmpegPath);
		log.info("generation:"+generation);
		for(int i=0;i<convertingFile.length;i++){
			
		
			if(!converting){
				break;
			}
			ffmpegExecutable.executingFile(convertingFile[i],i);
			
			ExplorerView.log.info("converting:"+convertingFile[i]);
			PlatformUI.getWorkbench().getDisplay().syncExec(new ConvertMonitorStartSubTask(convertingFile[i].getName()));
		ProcessMonitor monitor=null;
		Runtime runtime=Runtime.getRuntime();
		ArrayList<String> param=new ArrayList<String>();
		
		
		param.add(ffmpegPath);
		FLVInfomation flvInfo=new FFMpegFLVParser(ffmpegPath).parseFile(convertingFile[i]);
		
		if(convertingFile[i].getName().toLowerCase().endsWith(".flv")&&flvInfo.getVideoCodec().equals(FLVInfomation.FLV4) && PlatformUI.getPreferenceStore().getBoolean(FFMpegUI.DEMUX_SOME_VIDEO)){
			//demux action
			log.info("demux vp6");
			try {
				tmpAudio=File.createTempFile("vp6", ".mp3");
				tmpAudio.deleteOnExit();
				String command[]=FFMpegCommandUtil.makeCopyAudioCommand(ffmpegPath, convertingFile[i].getAbsolutePath(), tmpAudio.getAbsolutePath());
				SimpleCommandExecuter executer1=new SimpleCommandExecuter(command);
				executer1.execute();
				log.info("demuxed audio");
				tmpVideo=File.createTempFile("vp6", ".avi");
				tmpVideo.deleteOnExit();
				String command2[]=FFMpegCommandUtil.makeCopyVideoCommand(ffmpegPath, convertingFile[i].getAbsolutePath(), tmpVideo.getAbsolutePath());
				SimpleCommandExecuter executer2=new SimpleCommandExecuter(command2);
				executer2.execute();
				log.info("demuxed video");
				
				param.add("-f");
				param.add("mp3");
				
				param.add("-i");
				param.add(tmpAudio.getAbsolutePath());
				
				param.add("-i");
				param.add(tmpVideo.getAbsolutePath());
			} catch (IOException e) {
				cancel();
				e.printStackTrace();
				log.warn("faild vp6 special");
				return;
			}
		}else{
			param.add("-i");
			param.add(convertingFile[i].getAbsolutePath());
		}
		
		
		
		if(isImageExport(extension)){
			param.add("-f");
			param.add("image2");
			param.add("-ss");
			param.add(store.getString(ShareSettingPage.IMAGE_TIME));
			param.add("-vframes");
			param.add("1");
		}else{
		param.add("-b");
		param.add(""+store.getInt(ShareSettingPage.VIDEO_BITRATE)+"k");
		param.add("-ab");
		param.add(""+store.getInt(ShareSettingPage.AUDIO_BITRATE)+"k");
		param.add("-ar");
		param.add(""+store.getInt(ShareSettingPage.EXPORT_WAVE_SAMPLERATE));
		param.add("-ac");
		param.add(""+store.getInt(ShareSettingPage.EXPORT_WAVE_CHANNEL));
		
		String fps=ShareSettingPage.getVideoFps(store);
		if(fps!=null){
		param.add("-r");
		param.add(fps);
		}
		
		String size=ShareSettingPage.getVideoSize(store);
		if(size!=null){
		param.add("-s");
		param.add(size);
		}
		
		String optionString=store.getString(ShareSettingPage.FFMPEG_OPTION);
		
		
	
		
		if(extension.equals("avi")){
			String vtag=null;
			
			//param.add(store.getString(ShareSettingPage.VIDEO_CODEC));
			String avicodec=store.getString(AVISettingPage.AVI_VIDEO_CODEC);
			if(avicodec.equals(FFMpegOptions.CODEC_VIDEO_XVID)){
				//XVID need aspect
				param.add("-aspect");
				param.add("4:3");
				vtag="XVID";
				//fix odd size.
				if(size==null && FFMpegUtils.isOdd(flvInfo.getVideoWidth(), flvInfo.getVideoHeight())){
					param.add("-s");
					String newSize=FFMpegUtils.fixOddSize(flvInfo.getVideoWidth(), flvInfo.getVideoHeight());
					param.add(newSize);
				}
				
				}else if(avicodec.equals(FFMpegOptions.CODEC_VIDEO_H264)){
					//some ffmpeg need
					param.add("-rc_eq");
					param.add("\"blurCplx^(1-qComp)\"");
				}
			else if(avicodec.equals(FFMpegOptions.CODEC_COPY)){
				if(flvInfo.getVideoCodec().equals(FFMpegOptions.CODEC_VIDEO_XVID)){
					vtag="XVID";	
				}else if(flvInfo.getVideoCodec().equals(FFMpegOptions.CODEC_VIDEO_VP6F)){
					vtag="VP62";//for open vp6vfw.dll	
				}
			}
			
			param.add("-vcodec");
			param.add(FFMpegPreference.toSuiteVideoCodec(avicodec,generation));
			if(vtag!=null){
				param.add("-vtag");
				param.add(vtag);
			}
			String audioCodec=store.getString(AVISettingPage.AVI_AUDIO_CODEC);
			if(audioCodec.equals(FFMpegOptions.NONE)){//no audio
				param.add("-an");
			}else{
				param.add("-acodec");
				param.add(FFMpegPreference.toSuiteAudioCodec(store.getString(AVISettingPage.AVI_AUDIO_CODEC),generation));
				
			}
			
		}else if(extension.equals("wmv")){
			
//			changed for more stable working.
			param.add("-vcodec");
			param.add(store.getString(WMVSettingPage.WMV_VIDEO_CODEC));
			param.add("-acodec");
			param.add(store.getString(WMVSettingPage.WMV_AUDIO_CODEC));
			
			if(FFMpegUtils.isOdd(flvInfo.getVideoWidth(), flvInfo.getVideoHeight())){
				param.add("-s");
				String newSize=FFMpegUtils.fixOddSize(flvInfo.getVideoWidth(), flvInfo.getVideoHeight());
				//log.infooldsize:"+flvInfo.getVideoWidth()+"x"+flvInfo.getVideoHeight());
				//log.infonewsize:"+newSize);
				param.add(newSize);
				
			}
			
		}else if(extension.equals("mp3")){
			//some ffmpeg,unbeliably encode as mp2
			param.add("-acodec");
			param.add(FFMpegPreference.toSuiteAudioCodec(FFMpegOptions.CODEC_AUDIO_MP3,generation));
		}else if(extension.equals("mpg")){
			//changed for more stable working.
			param.add("-vcodec");
			param.add(store.getString(MPEGSettingPage.MPEG_VIDEO_CODEC));
			param.add("-acodec");
			param.add(store.getString(MPEGSettingPage.MPEG_AUDIO_CODEC));
			//maybe good for something.
			//param.add(FFMpegPreference.OPTION_TARGET);
			//param.add(FFMpegPreference.TARGET_NTSC_DVD);
			
//			Special trick CBR Encoding
			if(store.getString(MPEGSettingPage.MPEG_TYPE).equals(MPEGSettingPage.MPEG_TYPE_CBR)){
				param.add("-maxrate");
				param.add(""+store.getInt(ShareSettingPage.VIDEO_BITRATE)+"k");
				param.add("-minrate");
				param.add(""+store.getInt(ShareSettingPage.VIDEO_BITRATE)+"k");
				param.add("-bufsize");
				param.add("128k");
			}
		}
		
		
		
		String[] options=optionString.split(" ");//buggy
		for (int j = 0; j < options.length; j++) {
			param.add(options[j]);	
		}
		
		
		}
		//set export directory
		File currentFile=convertingFile[i];
		if(exportBaseDir!=null){
			currentFile=new File(exportBaseDir,convertingFile[i].getName());
			}
		//check if no folder.
		
		param.add(FileNameUtils.getChangedExtensionName(currentFile,extension));
		try {
			String arg[]=(String[])param.toArray(new String[0]);
			
			//special PSP setting
			if(extension.equals("psp")){
				PSPMovieSetting[] settings = PSPMovieSettingTableViewer.toPSPMovieSettings(Akj_betasPlugin.getDefault().getPreferenceStore().getString(OldPSPSettingPage.EXPORT_MOVIE_SETTINGS));
				if(settings.length==0){
					log.warn("psp setting not found");
					return;
				}else{
					//use zero setting
					PSPFFMpegPreference preference=PSPConvertTabBuilder.toPreference(settings[0]);
					
					preference.setFfmpegPath(ffmpegPath);
					if(tmpAudio!=null && tmpVideo!=null){
						arg=preference.toCommand(new FFMpegInput[]{new FFMpegInput(tmpAudio.getAbsolutePath(),"mp3"),new FFMpegInput(tmpVideo.getAbsolutePath())},FileNameUtils.getChangedExtensionName(currentFile,"mp4"));
						
					}else{
						arg=preference.toCommand(convertingFile[i].getAbsolutePath(), null, FileNameUtils.getChangedExtensionName(currentFile,"mp4"));
						}
					}
				}
			
			debugArray(arg);
			currentProcess = runtime.exec(arg);
			monitor=new ProcessMonitor(currentProcess,Akj_betasPlugin.getDefault().getProcessPrinter());
			monitor.startMonitor();
			
			
			try {
				currentProcess.waitFor();
				
				int exitValue=currentProcess.exitValue();
				if(exitValue==0){
					//guess complete
					if(extension.equals("psp")){
						if(store.getBoolean(ShareSettingPage.IS_DELETE_MP4)){
							convertingFile[i].delete();
							fileDeleted=true;
						}
					}else if(extension.equals("avi")){
						if(store.getBoolean(ShareSettingPage.IS_DELETE_AVI)){
							convertingFile[i].delete();
							fileDeleted=true;
						}
					}else if(extension.equals("mpg")){
						if(store.getBoolean(ShareSettingPage.IS_DELETE_MPG)){
							convertingFile[i].delete();
							fileDeleted=true;
						}
					}else if(extension.equals("wmv")){
						if(store.getBoolean(ShareSettingPage.IS_DELETE_WMV)){
							convertingFile[i].delete();
							fileDeleted=true;
						}
					}
				}
			} catch (InterruptedException e) {
			
				e.printStackTrace();
			}
			
		} catch (IOException e) {
		
			e.printStackTrace();
		}finally{
		
		if(tmpAudio!=null){
			tmpAudio.delete();
			tmpAudio=null;
			}
		
		if(tmpVideo!=null){
			tmpVideo.delete();
			tmpVideo=null;
			}
		}
		
		monitor.stop();
		PlatformUI.getWorkbench().getDisplay().syncExec(new ConvertMonitorProcess());
		

		}
		if(fileDeleted){
			PlatformUI.getWorkbench().getDisplay().syncExec(new ReloadView());
		}
		
		ffmpegExecutable.executingFile(null,-1);//for finish
		
		PlatformUI.getWorkbench().getDisplay().syncExec(new ConvertMonitorDone());
		
		PlatformUI.getWorkbench().getDisplay().syncExec(new FinishAction());
		//finish
		//PlatformUI.getWorkbench().getDisplay().syncExec(new EnableControl(convertButton));
		
		
		
	}
	public class ReloadView extends Thread{
		public void run(){
			ffmpegExecutable.reload();//TODO more elegant
		}
	}
	public class FinishAction extends Thread{
		public void run(){
			ffmpegExecutable.finishExecute();
		}
	}
	

	public File[] getFileList(){
		return convertingFile;
	}
	
	
	public class ConvertMonitorStartSubTask extends Thread{
		String name;
		public ConvertMonitorStartSubTask(String name){
			this.name=name;
		}
		public void run(){
			if(ffmpegExecutable.getProgressMonitor()!=null)
				ffmpegExecutable.getProgressMonitor().subTask(name);
		}
	}
	
	public class ConvertMonitorProcess extends Thread{
		
		public void run(){
			if(ffmpegExecutable.getProgressMonitor()!=null)
				ffmpegExecutable.getProgressMonitor().worked(1);
		}
	}
	
	public class ConvertMonitorDone extends Thread{
		public void run(){
			if(ffmpegExecutable.getProgressMonitor()!=null)
				ffmpegExecutable.getProgressMonitor().done();
		}
	}

	public FFMpegExecutable getFfmpegExecutable() {
		return ffmpegExecutable;
	}
/*
	public void setFfmpegExecutable(FFMpegExecutable ffmpegExecutable) {
		this.ffmpegExecutable = ffmpegExecutable;
	}*/
	public String getExtension() {
		return extension;
	}
	public void setExtension(String extension) {
		this.extension = extension;
	}
	public File[] getConvertingFile() {
		return convertingFile;
	}
	public void setConvertingFile(File[] convertingFile) {
		this.convertingFile = convertingFile;
	}
	public File getExportBaseDir() {
		return exportBaseDir;
	}
	public void setExportBaseDir(File exportBaseDir) {
		this.exportBaseDir = exportBaseDir;
	}

}